package nancal.mp.mvc.ops

import nancal.mp.db.mongo.JenkinsLanguageEnum
import nancal.mp.db.mongo.entity.dev.*
import nancal.mp.db.mongo.mor
import nancal.mp.model.K8sDeployServiceModel
import nancal.mp.model.replaceVarModel
import nancal.mp.service.getK8sDeploymentYamlContent
import nbcp.base.annotation.*
import nbcp.base.annotation.mvc.AdminSysOpsAction
import nbcp.base.annotation.mvc.OpenAction
import nbcp.base.comm.JsonMap
import nbcp.base.comm.MvnDependencyBasicData
import nbcp.base.extend.*
import nbcp.base.json.*
import nbcp.base.utils.MyUtil
import nbcp.myoql.db.mongo.query
import nbcp.myoql.db.mongo.queryById
import org.slf4j.LoggerFactory
import org.springframework.web.bind.annotation.*
import java.time.LocalDateTime

@RequestMapping("/ops/cmd")
@RestController
@AdminSysOpsAction
class OpsCmdController {
    companion object {
        private val logger = LoggerFactory.getLogger(this::class.java.declaringClass)
    }


    /**
     * 依赖检查
     * @param content: 依赖项，形如：com.alibaba.nacos:nacos-api:jar:1.4.1:compile 每行一个，去重，排序过。
     */
    @PostMapping("/mvn-dependency-check", produces = arrayOf("text/plain"))
    fun dependencyCheck(
        @RequestBody content: String
    ): String {
        var hooks = mor.dev.appDeployPipelineHook.query()
            .where { it.language mongoEquals JenkinsLanguageEnum.Java }
            .where { it.define.component.mongoHasValue() }
            .toList()
            .filter { it.define.component.HasValue };


        var msgs = mutableListOf<String>()
        content.split("\n")
            .map {
                var item = it.split(":")
                if (item.size != 5) {
                    return@map MvnDependencyBasicData();
                }

                if (item.get(2) != "jar") {
                    return@map MvnDependencyBasicData();
                }

                if (item.get(4) != "compile") {
                    return@map MvnDependencyBasicData();
                }

                return@map MvnDependencyBasicData(item.get(0), item.get(1), item.get(3));
            }
            .filter { it.groupId.HasValue && it.version.HasValue }
            .forEach { dependency ->

                //先校验 Hook
                hooks.forEach { hook ->
                    mvnDependencyCheckCheck(hook, dependency)
                        .apply {
                            if (this.any()) {
                                msgs.add(this)
                            }
                        }
                }
            }

        return msgs.joinToString("\n")
    }

    @PostMapping("/tar-docker-layers", produces = arrayOf("text/plain"))
    fun getLayers(
        @RequestBody content: String,
        @RequestParam target:String
    ): String {
        var manifest = content.FromListJson(JsonMap::class.java)

        if (manifest.any() == false) {
            return "";
        }

        return ((manifest.first() as Map<String, Any>).get("Layers") as List<String>)
            .map { """
echo "tar xf $it  --warning=no-timestamp  -C ${target}"
tar xf $it  --warning=no-timestamp  -C ${target}
""" }
            .joinToString("\n");
    }


    @PostMapping("/get-start-shell", produces = arrayOf("text/plain"))
    fun getStartSh(
        @Require logId: String,
        @RequestBody content: String
    ): String {
        var inspects = content.FromListJson(JsonMap::class.java)

        if (inspects.any() == false) {
            return "";
        }

        var jenkinsLog: JenkinsLog = mor.dev.jenkinsLog.queryById(logId).toEntity()
            .must()
            .elseThrow { "找不到JenkinsLog ${logId}" }

        if (jenkinsLog.language != JenkinsLanguageEnum.Java) {
            return ""
        }

        var config = (inspects.first() as Map<String, Any>).get("Config") as Map<String, Any?>;
        var envs = getEnvs(config, jenkinsLog)

        var cmd = (config.get("Cmd") as List<String>)
            .last()
            .remove("--server.port=80")
            .replace(""" java """, "  ${'$'}JDK_${jenkinsLog.languageVersion}/bin/java  ")
        return """#!/bin/bash
            
# ${LocalDateTime.now().AsString()}
# ${jenkinsLog.language}: ${jenkinsLog.languageVersion}

#在外部执行 export JDK_${jenkinsLog.languageVersion}=JDK_HOME位置


${envs}

${cmd}  ${'$'}*
        """
    }

    private fun getEnvs(
        dockerConfig: Map<String, Any?>,
        jenkinsLog: JenkinsLog
    ): String {
        var docker_envs = (dockerConfig.get("Env") as List<String>)
            .map {
                var eqIndex = it.indexOf("=");
                if (eqIndex < 0) {
                    return@map it to ""
                }

                return@map it.Slice(0, eqIndex) to it.Slice(eqIndex + 1)
            }
            .toMap()
            .filter { it.key.IsInItems("JAVA_OPTS", "PROFILE", "JAVA_ARGS", "APP_GROUP", "APP_NAME") };


        var envs = (docker_envs + getK8sEnvs(jenkinsLog))
            .map {
                return@map """${it.key}="${it.value}""""
            }
            .joinToString("\n") + "\n"
        return envs
    }


    /**
     * 从 K8sDeployment Yaml 中获取容器变量。
     */
    private fun getK8sEnvs(jenkinsLog: JenkinsLog?): Map<String, String> {
        if (jenkinsLog == null) return mapOf();

        var log = jenkinsLog

        if (log.gitData == null) {
            return mapOf();
        }


        //replace k8s var
        var def = K8sDeployServiceModel.load(log);
        var yaml = "";
        if (log.currentGitFolder.config.k8sDeployment.id.HasValue) {

            yaml = mor.dev.userK8sDeployment.queryById(log.currentGitFolder.config.k8sDeployment.id)
                .toEntity()
                ?.yaml ?: ""
        }

        if (yaml.isEmpty()) {
            yaml = def.language.getK8sDeploymentYamlContent(def.languageVersion, def.targetEnv);
        }

        if (yaml.isEmpty()) {
            return mapOf()
        }


        var yamlMap = yaml.replaceVarModel(def)
            .FromYamlText<JsonMap>()

        var container =
            (yamlMap.getValueByWbsPath("spec.template.spec.containers") as List<*>).first() as Map<String, Any?>
        var envs = (container.getValueByWbsPath("env") as List<Map<String, String>>).map {
            it.get("name").AsString() to it.get("value").AsString()
        }.toMap();

        return envs;
    }

    /**
     * 从系统定义中检测是否有不安全的Jar包。
     */
    private fun mvnDependencyCheckCheck(hook: AppDeployPipelineHook, dependency: MvnDependencyBasicData): String {
        if (hook.define.component.isEmpty()) return "";
        if (hook.define.minVersion.isEmpty() && hook.define.maxVersion.isEmpty()) return "";


        if (hook.define.component != (dependency.groupId + ":" + dependency.artifactId)) {
            return "";
        }

        versionBetweenCheck(dependency.version, hook.define.minVersion, hook.define.maxVersion)
            .apply {
                if (this == false) {
                    var tail = "";
                    if (hook.define.minVersion.HasValue) {
                        tail += " >= ${hook.define.minVersion}"
                    }
                    if (hook.define.maxVersion.HasValue) {
                        tail += " <= ${hook.define.maxVersion}"
                    }
                    return "maven依赖检查 ${dependency.groupId}:${dependency.artifactId} 必须 ${tail} !"
                }
            }

        return ""
    }

    private fun versionBetweenCheck(version: String, minVersion: String, maxVersion: String): Boolean {
        if (version.isEmpty()) return true;

        if (minVersion.HasValue && MyUtil.compareVersion(version, minVersion) < 0) {
            return false
        }

        if (maxVersion.HasValue && MyUtil.compareVersion(version, maxVersion) > 0) {
            return false
        }
        return true;
    }

//    @PostMapping("/mvn-switch-pom", consumes = arrayOf("text/plain"), produces = arrayOf("text/plain"))
//    fun switchPom(
//        @Require msDeployEnv: MicroServiceDeployEnvEnum,
//        @RequestBody content: String,
//        response: HttpServletResponse
//    ): String {
//        var reader = SAXReader();
//        var doc = reader.read(content.reader());
//        var root = doc.rootElement
//        var parent = root.element("parent")
//
//        var artifactId = parent.element("artifactId").text
//        var relativePath = parent.element("relativePath")?.text.AsString()
//
//        if (artifactId.contains(msDeployEnv.toString(), ignoreCase = true)) {
//            return ""
//        }
//
//        if (msDeployEnv == MicroServiceDeployEnvEnum.k8s) {
//            parent.element("artifactId").text =
//                artifactId.replace("nacos", msDeployEnv.toString().lowercase(), ignoreCase = true)
//            parent.element("relativePath").text =
//                relativePath.replace("nacos", msDeployEnv.toString().lowercase(), ignoreCase = true)
//        } else if (msDeployEnv == MicroServiceDeployEnvEnum.nacos) {
//            parent.element("artifactId").text =
//                artifactId.replace("k8s", msDeployEnv.toString().lowercase(), ignoreCase = true)
//            parent.element("relativePath").text =
//                relativePath.replace("k8s", msDeployEnv.toString().lowercase(), ignoreCase = true)
//        }
//
//        artifactId = parent.element("artifactId").text
//        relativePath = parent.element("relativePath").text
//
//        if (artifactId.contains(msDeployEnv.toString()) == false) {
//            var msg = "pom.xml内容的 parent.artifactId 不包含 ${
//                MicroServiceDeployEnvEnum.values().map { it.toString() }.joinToString(",")
//            }！不能动态切换微服务环境！";
//
//            logger.warn(msg);
//            return "";
////            throw RuntimeException(
////                "pom.xml内容的 parent.artifactId 不包含 ${
////                    MicroServiceDeployEnvEnum.values().map { it.toString() }.joinToString(",")
////                }！不能动态切换微服务环境！"
////            )
//        }
//
//        return doc.asXML();
//    }


//    @GetMapping("/ms-deploy-env-yml")
//    fun getDefNacosYml(
//        @Require msDeployEnv: MicroServiceDeployEnvEnum,
//        response: HttpServletResponse
//    ) {
//        var fileContent = FileContent();
//        if (msDeployEnv == MicroServiceDeployEnvEnum.nacos) {
//            fileContent.fileName = "bootstrap-nacos.yml"
//            fileContent.content = """
//spring:
//  cloud:
//    nacos:
//      discovery:
//        server-addr: nacos:8848
//        namespace: ＄{app.group}
//      config:
//        file-extension: yml
//        enabled: true
//        server-addr: ＄{spring.cloud.nacos.discovery.server-addr}
//        namespace: ＄{spring.cloud.nacos.discovery.namespace}
//
//logging:
//  config: classpath:logback-skywalking.xml
//""".replace('＄', '$')
//        } else {
//            fileContent.fileName = "bootstrap-k8s.yml"
//            fileContent.content = """
//spring:
//  main:
//    allow-bean-definition-overriding: true
//  cloud:
//    kubernetes:
//      reload:
//        enabled: true
//        monitoring-config-maps: true
//        monitoring-secrets: true
//        strategy: restart_context
//        mode: event
//      config:
//        enabled: true
//      client:
//        master-url: https://kubernetes.default.svc
//        trustCerts: true
//management:
//  endpoint:
//    restart:
//      enabled: true
//  endpoints:
//    web:
//      exposure:
//        include: restart
//""".replace('＄', '$')
//        }
//
//        response.outputStream.write(fileContent.content.toByteArray(const.utf8))
//        response.setDownloadFileName(fileContent.fileName)
//    }
}
